Skip to content

Refactor/enssdk refactor continued#1908

Merged
shrugs merged 62 commits intomainfrom
refactor/enssdk-refactor-continued
Apr 14, 2026
Merged

Refactor/enssdk refactor continued#1908
shrugs merged 62 commits intomainfrom
refactor/enssdk-refactor-continued

Conversation

@shrugs
Copy link
Copy Markdown
Collaborator

@shrugs shrugs commented Apr 9, 2026

closes #1876

Reviewer Focus (Read This First)

  1. resolution libs now operate over (normalized) InterpretedNames — deferring further constraints to Resolution API: Further constrain the type of names used for resolution #1920
  2. NormalizedAddress is an unbranded alias for 0x{string}; all indexer/ens-referrals callsites cast rather than validate — spot-check that boundary validation still happens where it matters. the important entrypoints for the ens-referrals, ensanalytics, registrar-actions, and associated modules have all been checked and are enforced by zod schemas.
  3. new enskit/react submodule export + EnsureInterpretedName relocation — verify the package surface is what you expect

What Changed (Concrete)

  1. removed NormalizedName; resolution libs + callsites now use InterpretedName
  2. introduced NormalizedAddress (unbranded alias for 0x{string}) replacing asLowerCaseAddress + makeLowerCaseAddressSchema; updated all indexer + ens-referrals callsites
  3. added enskit/react submodule export; moved EnsureInterpretedName there
  4. expanded literalNameToInterpretedName logic; added nameToInterpretedName helper and tests
  5. omnigraph: local resolvers, bigint deserialization, bigint[] support, semantic scalars (Duration moved to enssdk)
  6. encoded-referrer: DRY'd encoded labelhash parsing, fixed size check, decodeEncodedReferrer now returns NormalizedAddress
  7. root name handling in parse-reverse-name; ENS_ROOT_NAME / ENS_ROOT_NODE cleanup
  8. dropped @urql/introspection codegen and the separate generated/introspection.ts, can use the gql.tada generated file for urql introspection
  9. misc: typos/docstrings

Design & Planning

Self-Review

  • Bugs caught: referrer size check, root name in parse-reverse-name, partial-data guard in cache-exchange, encoded labelhash validation in interpretation
  • Logic simplified: ensure-interpreted-name streamlined, validateAddress refactored, toNormalizedAddress input type relaxed
  • Naming / terminology improved: NormalizedNameInterpretedName project-wide; AddressNormalizedAddress where the invariant holds
  • Dead / unnecessary code removed: dropped ambiguous readFragment re-export in enskit/react/omnigraph; removed NormalizedName type + schema

Downstream & Consumer Impact

  • Public APIs affected: enssdk type exports (NormalizedName removed), enskit gains /react submodule, omnigraph scalars reshuffled
  • Docs updated: schema.graphql regenerated, enssdk _lib/README.md, AGENTS.md note on running test files
  • Decisions worth calling out: NormalizedAddress is intentionally unbranded — it's a documentation alias, not a runtime invariant. We should probably brand it in the near future?

Testing Evidence

  • Testing performed: added tests for interpreted-names-and-labels, encoded-referrer, packetToBytes, resolve-with-universal-resolver integration, omnigraph builder
  • Known gaps: no e2e coverage for the full indexer re-run — type system carries most of the refactor safety
  • What reviewers have to reason about manually: the NormalizedAddress cast sites (unbranded → trust the caller)

Scope Reductions

Risk Analysis

  • Risk areas: any place an InterpretedName is passed where a literal name was previously expected; NormalizedAddress casts on data from untrusted sources
  • Mitigations / rollback: revert is clean — changes are type-level + mechanical
  • Named owner if this causes problems: @shrugs

Pre-Review Checklist (Blocking)

  • I reviewed every line of this diff and understand it end-to-end
  • I'm prepared to defend this PR line-by-line in review
  • I'm comfortable being the on-call owner for this change
  • Relevant changesets are included (or explicitly not required)

@shrugs shrugs requested a review from a team as a code owner April 9, 2026 21:42
Copilot AI review requested due to automatic review settings April 9, 2026 21:42
@vercel
Copy link
Copy Markdown
Contributor

vercel bot commented Apr 9, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
admin.ensnode.io Ready Ready Preview, Comment Apr 14, 2026 7:37pm
ensnode.io Ready Ready Preview, Comment Apr 14, 2026 7:37pm
ensrainbow.io Ready Ready Preview, Comment Apr 14, 2026 7:37pm

@changeset-bot
Copy link
Copy Markdown

changeset-bot bot commented Apr 9, 2026

🦋 Changeset detected

Latest commit: ce8af05

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 24 packages
Name Type
enskit Major
@ensnode/enskit-react-example Patch
ensindexer Major
ensadmin Major
ensrainbow Major
ensapi Major
fallback-ensapi Major
enssdk Major
enscli Major
ensskills Major
@ensnode/datasources Major
@ensnode/ensrainbow-sdk Major
@ensnode/ensdb-sdk Major
@ensnode/ensnode-react Major
@ensnode/ensnode-sdk Major
@ensnode/ponder-sdk Major
@ensnode/ponder-subgraph Major
@ensnode/shared-configs Major
@docs/ensnode Major
@docs/ensrainbow Major
@docs/mintlify Major
@namehash/ens-referrals Major
@namehash/namehash-ui Major
@ensnode/integration-test-env Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Apr 9, 2026

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 0ff22d59-5ddd-40c8-af4c-9909a31c6935

📥 Commits

Reviewing files that changed from the base of the PR and between ae3859d and ce8af05.

⛔ Files ignored due to path filters (2)
  • packages/enssdk/src/omnigraph/generated/introspection.ts is excluded by !**/generated/**
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (67)
  • .changeset/humble-mice-listen.md
  • AGENTS.md
  • apps/ensapi/package.json
  • apps/ensapi/src/lib/ensanalytics/referrer-leaderboard/database-v1.ts
  • apps/ensapi/src/lib/ensanalytics/referrer-leaderboard/database.ts
  • apps/ensapi/src/lib/protocol-acceleration/get-primary-name-from-index.ts
  • apps/ensapi/src/lib/resolution/forward-resolution.ts
  • apps/ensapi/src/lib/resolution/resolve-with-universal-resolver.integration.test.ts
  • apps/ensapi/src/omnigraph-api/builder.test.ts
  • apps/ensapi/src/omnigraph-api/lib/find-domains/layers/base-domain-set.ts
  • apps/ensapi/src/omnigraph-api/lib/find-domains/layers/filter-by-owner.ts
  • apps/ensapi/src/omnigraph-api/lib/write-graphql-schema.ts
  • apps/ensapi/src/omnigraph-api/schema/permissions.integration.test.ts
  • apps/ensapi/src/omnigraph-api/schema/scalars.ts
  • apps/ensindexer/src/lib/maybe-heal-label-by-addr-reverse-subname.test.ts
  • apps/ensindexer/src/lib/maybe-heal-label-by-addr-reverse-subname.ts
  • apps/ensindexer/src/lib/trace-transaction-helpers.ts
  • apps/ensindexer/src/plugins/subgraph/plugins/subgraph/handlers/Registry.ts
  • apps/ensindexer/src/plugins/subgraph/shared-handlers/NameWrapper.ts
  • examples/enskit-react-example/src/DomainView.tsx
  • packages/datasources/src/invariants.test.ts
  • packages/ens-referrals/src/address.ts
  • packages/ens-referrals/src/rank.ts
  • packages/ens-referrals/src/referrer-detail.ts
  • packages/ens-referrals/src/referrer-metrics.ts
  • packages/ens-referrals/src/v1/address.ts
  • packages/ens-referrals/src/v1/api/zod-schemas.ts
  • packages/ens-referrals/src/v1/award-models/pie-split/metrics.ts
  • packages/ens-referrals/src/v1/award-models/rev-share-cap/aggregations.ts
  • packages/ens-referrals/src/v1/award-models/rev-share-cap/api/zod-schemas.ts
  • packages/ens-referrals/src/v1/award-models/rev-share-cap/leaderboard.ts
  • packages/ens-referrals/src/v1/award-models/rev-share-cap/metrics.ts
  • packages/ens-referrals/src/v1/award-models/rev-share-cap/referral-event.ts
  • packages/ens-referrals/src/v1/award-models/rev-share-cap/rules.ts
  • packages/ens-referrals/src/v1/award-models/shared/rank.ts
  • packages/ens-referrals/src/v1/edition-metrics.ts
  • packages/ens-referrals/src/v1/referrer-metrics.ts
  • packages/enskit/src/react/components/ensure-interpreted-name.tsx
  • packages/enskit/src/react/omnigraph/_lib/README.md
  • packages/enskit/src/react/omnigraph/_lib/by-id-lookup-resolvers.ts
  • packages/enskit/src/react/omnigraph/_lib/cache-exchange.ts
  • packages/enskit/src/react/omnigraph/_lib/local-bigint-resolvers.test.ts
  • packages/enskit/src/react/omnigraph/_lib/local-bigint-resolvers.ts
  • packages/enskit/src/react/omnigraph/index.ts
  • packages/ensnode-sdk/src/ensapi/api/registrar-actions/response.ts
  • packages/ensnode-sdk/src/registrars/encoded-referrer.test.ts
  • packages/ensnode-sdk/src/registrars/encoded-referrer.ts
  • packages/ensnode-sdk/src/shared/interpretation/interpret-record-values.ts
  • packages/ensnode-sdk/src/shared/zod-schemas.test.ts
  • packages/ensnode-sdk/src/shared/zod-schemas.ts
  • packages/enssdk/src/_lib/README.md
  • packages/enssdk/src/lib/address.test.ts
  • packages/enssdk/src/lib/address.ts
  • packages/enssdk/src/lib/ids.ts
  • packages/enssdk/src/lib/interpreted-names-and-labels.ts
  • packages/enssdk/src/lib/labelhash.ts
  • packages/enssdk/src/lib/names.test.ts
  • packages/enssdk/src/lib/names.ts
  • packages/enssdk/src/lib/normalization.ts
  • packages/enssdk/src/lib/parse-reverse-name.test.ts
  • packages/enssdk/src/lib/parse-reverse-name.ts
  • packages/enssdk/src/lib/reverse-name.ts
  • packages/enssdk/src/lib/types/evm.ts
  • packages/enssdk/src/omnigraph/graphql.ts
  • packages/enssdk/src/omnigraph/index.ts
  • packages/enssdk/src/omnigraph/introspection.ts
  • packages/enssdk/tsconfig.json

📝 Walkthrough

Walkthrough

Comprehensive refactoring consolidating address and temporal type handling by migrating from scattered implementations to unified enssdk definitions. Replaces legacy address normalization (asLowerCaseAddresstoNormalizedAddress), moves UnixTimestamp/Duration type definitions to enssdk, transitions from Name/NormalizedName to InterpretedName, updates ROOT_NODE to ENS_ROOT_NODE, strengthens GraphQL scalar mappings, and adds interpreted name validation components.

Changes

Cohort / File(s) Summary
Address Normalization — Core Address Functions
packages/enssdk/src/lib/address.ts, packages/enssdk/src/lib/address.test.ts
Added isNormalizedAddress, toNormalizedAddress, asNormalizedAddress functions; replaced asLowerCaseAddress with normalized variants; updated test suites.
Address Normalization — Zod Schemas & Validation
packages/ensnode-sdk/src/shared/zod-schemas.ts, packages/ensnode-sdk/src/shared/zod-schemas.test.ts, apps/ensapi/src/lib/handlers/params.schema.ts, apps/ensapi/src/handlers/api/explore/registrar-actions-api.routes.ts, apps/ensapi/src/handlers/ensanalytics/ensanalytics-api*.routes.ts, packages/ens-referrals/src/**/zod-schemas.ts
Changed address schema validators from makeLowercaseAddressSchema to makeNormalizedAddressSchema.
Address Normalization — Handler & API Type Updates
apps/ensapi/src/omnigraph-api/builder.ts, apps/ensapi/src/omnigraph-api/schema/scalars.ts, apps/ensindexer/src/plugins/ensv*/handlers/*.ts, apps/ensindexer/src/plugins/*/handlers/*.ts
Updated event argument types from Address to NormalizedAddress across ENSv1/v2 handlers and resolver handlers.
Address Normalization — Business Logic
packages/ens-referrals/src/**/*.ts, apps/ensapi/src/lib/ensanalytics/referrer-leaderboard/*.ts, packages/ensnode-sdk/src/registrars/encoded-referrer.ts
Updated referrer/address parameter types and validation functions; changed buildEncodedReferrer/decodeEncodedReferrer signatures.
Address Normalization — Indexer Modules
apps/ensindexer/src/config/validations.ts, apps/ensindexer/src/lib/trace-transaction-helpers.ts, apps/ensindexer/src/lib/heal-addr-reverse-subname-label.ts, packages/ensdb-sdk/src/*/registrars.schema.ts
Updated address validation/tracing and event handler types to use NormalizedAddress.
Names & Interpreted Labels Refactoring
packages/enssdk/src/lib/interpreted-names-and-labels.ts, packages/enssdk/src/lib/interpreted-names-and-labels.test.ts, packages/enssdk/src/lib/names.ts, packages/enssdk/src/lib/names.test.ts
Added literalNameToInterpretedName, refined isInterpretedLabel/isInterpretedName, changed getParentNameFQDN to getParentInterpretedName, removed NormalizedName.
Names & Reverse Name Resolution
packages/enssdk/src/lib/reverse-name.ts, packages/enssdk/src/lib/parse-reverse-name.ts, packages/enssdk/src/lib/parse-reverse-name.test.ts
Updated return types to InterpretedName/InterpretedLabel; changed address parameter from Address to NormalizedAddress.
ENS Root Node Constants Migration
packages/enssdk/src/lib/constants.ts, packages/enssdk/src/lib/types/ens.ts, apps/ensapi/src/omnigraph-api/lib/get-canonical-path.ts, apps/ensindexer/src/lib/subgraph/subgraph-helpers.ts, apps/ensindexer/src/plugins/subgraph/plugins/subgraph/handlers/Registry.ts
Replaced ROOT_NODE with ENS_ROOT_NODE; removed NormalizedName type export.
Forward/Reverse Resolution Updates
apps/ensapi/src/lib/resolution/forward-resolution.ts, apps/ensapi/src/lib/resolution/reverse-resolution.ts, apps/ensapi/src/lib/resolution/resolve-calls-and-results.ts, apps/ensapi/src/lib/resolution/resolve-with-universal-resolver.ts, apps/ensapi/src/lib/resolution/resolve-with-universal-resolver.integration.test.ts, apps/ensapi/src/lib/resolution/packetToBytes.test.ts
Changed function signatures to accept InterpretedName; updated address validation; added integration tests.
Protocol Acceleration Refactoring
apps/ensapi/src/lib/protocol-acceleration/find-resolver.ts, apps/ensapi/src/lib/protocol-acceleration/get-primary-name-from-index.ts, apps/ensindexer/src/lib/protocol-acceleration/resolver-db-helpers.ts, apps/ensindexer/src/plugins/protocol-acceleration/handlers/*.ts
Updated parameter types to use InterpretedName and NormalizedAddress; added asLiteralName coercions.
GraphQL Omnigraph & Scalar Definitions
packages/enssdk/src/omnigraph/graphql.ts, packages/enssdk/src/omnigraph/introspection.ts, packages/enskit/src/react/omnigraph/graphql.ts, apps/ensapi/src/omnigraph-api/builder.ts, apps/ensapi/src/omnigraph-api/builder.test.ts
Updated Address scalar output to NormalizedAddress; added OmnigraphScalars type; reorganized introspection generation.
React Omnigraph Cache & Resolvers
packages/enskit/src/react/omnigraph/_lib/*.ts, packages/enskit/src/react/omnigraph/client.ts, packages/enskit/src/react/omnigraph/lib/cache-exchange.ts
Extracted cache resolver logic; added byIdLookupResolvers, localBigIntResolvers, mergeResolverMaps; updated cache configuration.
Enskit Components & Package Exports
packages/enskit/src/react/components/ensure-interpreted-name.tsx, packages/enskit/src/react/components/index.tsx, packages/enskit/src/react/index.ts, packages/enskit/package.json, packages/enskit/tsup.config.ts, packages/enskit/biome.jsonc
Added EnsureInterpretedName React component; exposed ./react subpath export; updated build configuration.
Type Imports Consolidation — Duration & UnixTimestamp
packages/enssdk/src/lib/types/shared.ts, packages/enssdk/src/lib/types/evm.ts, packages/ensnode-sdk/src/shared/types.ts, packages/ensnode-sdk/src/shared/datetime.ts, packages/ensnode-sdk/src/shared/cache/*.ts, packages/ensnode-sdk/src/shared/deserialize.ts, packages/ensnode-sdk/src/registrars/registrar-action.ts, packages/ensnode-sdk/src/indexing-status/*.ts, apps/ensapi/src/**, apps/ensadmin/src/**, apps/ensindexer/src/**, packages/ens-referrals/src/**, packages/namehash-ui/src/**
Migrated Duration/UnixTimestamp imports from scattered modules to enssdk as canonical source; added bigint variants (UnixTimestampBigInt, DurationBigInt, Wei).
Database Schema Typing
packages/ensdb-sdk/src/ensindexer-abstract/*.schema.ts
Added explicit $type<...>() annotations for InterpretedName, Node, NormalizedAddress columns.
Labelhash Parsing & Encoding
packages/enssdk/src/lib/labelhash.ts, apps/ensapi/src/lib/resolution/packetToBytes.test.ts
Added decodeEncodedLabelHash function; refactored isEncodedLabelHash.
Registrar & Referral Domain Logic
packages/ensnode-sdk/src/registrars/zod-schemas.ts, packages/ensnode-sdk/src/registrars/encoded-referrer.test.ts, packages/ensnode-sdk/src/tokenscope/name-token.ts, apps/ensindexer/src/lib/tokenscope/seaport-types.ts
Updated address/referrer types; changed parent-name resolution to use getParentInterpretedName.
Example App & Test Updates
examples/enskit-react-example/src/DomainView.tsx, apps/ensrainbow/src/commands/convert-csv-command.test.ts, apps/ensapi/src/omnigraph-api/schema/*.integration.test.ts, apps/ensapi/src/test/integration/find-*/*.ts, packages/ensnode-sdk/src/shared/interpretation/interpret-record-values.test.ts
Updated example app to use EnsureInterpretedName; refactored test assertions to use await expect().resolves pattern; updated GraphQL type expectations.
Documentation & Configuration
AGENTS.md, packages/enskit/src/react/omnigraph/_lib/README.md, packages/enssdk/src/_lib/README.md, .changeset/humble-mice-listen.md, packages/enskit/biome.jsonc, apps/ensapi/package.json
Updated workflow instructions; added module documentation; removed unused dependencies; adjusted linter overrides.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested labels

ensnode-sdk, enssdk, refactoring, types

Poem

🐰 From lowercase to normalized, we hop along,
InterpretedNames and RootNodes sing their song,
Duration and Timestamp now unified and bright,
Address fields strengthened—everything feels right!
⚡ The rabbit approves this grand refactoring flight!

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch refactor/enssdk-refactor-continued

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR continues the ENS SDK refactor by standardizing address normalization across the stack, tightening the “interpreted name” model, and updating downstream packages/apps to use the new types/helpers.

Changes:

  • Introduces NormalizedAddress + normalization helpers and updates GraphQL/Zod/address usage to consistently use lowercase EVM addresses.
  • Refactors ENS name utilities around InterpretedName (new parent/name-hierarchy helpers, removal of NormalizedName brand usage) and adds a UI helper component to enforce interpreted names.
  • Renames root constants (ROOT_NODEENS_ROOT_NODE, adds ENS_ROOT_NAME) and migrates many UnixTimestamp imports to come from enssdk.

Reviewed changes

Copilot reviewed 87 out of 88 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
packages/namehash-ui/src/components/registrar-actions/RegistrarActionCard.tsx Swap UnixTimestamp type import to enssdk.
packages/enssdk/src/omnigraph/graphql.ts Map GraphQL Address scalar to NormalizedAddress.
packages/enssdk/src/omnigraph/generated/schema.graphql Update scalar docs to reference enssdk + lowercase address semantics.
packages/enssdk/src/lib/types/evm.ts Add NormalizedAddress type and clarify EVM scalar docs.
packages/enssdk/src/lib/types/ens.ts Remove NormalizedName branded type export.
packages/enssdk/src/lib/parse-reverse-name.ts Normalize reverse-derived addresses via toNormalizedAddress.
packages/enssdk/src/lib/normalization.ts Drop NormalizedName type-guard; tweak error messages.
packages/enssdk/src/lib/names.ts Refactor hierarchy/parent helpers to use InterpretedName + ENS_ROOT_NAME.
packages/enssdk/src/lib/names.test.ts Update tests for new name helpers/constants.
packages/enssdk/src/lib/interpreted-names-and-labels.ts Add nameToInterpretedName; adjust casting helpers + docs.
packages/enssdk/src/lib/constants.ts Add ENS_ROOT_NAME / ENS_ROOT_NODE; type ROOT_RESOURCE.
packages/enssdk/src/lib/address.ts Add isNormalizedAddress/toNormalizedAddress/asNormalizedAddress.
packages/enssdk/src/lib/address.test.ts Add tests for new address normalization helpers.
packages/ensnode-sdk/src/tokenscope/name-token.ts Use getParentInterpretedName and handle root-parent null.
packages/ensnode-sdk/src/shared/zod-schemas.ts Rename lowercase-address schema to normalized-address schema.
packages/ensnode-sdk/src/shared/types.ts Source UnixTimestamp from enssdk for BlockRef.
packages/ensnode-sdk/src/shared/interpretation/interpret-record-values.ts Use InterpretedName + toNormalizedAddress for record interpretation.
packages/ensnode-sdk/src/shared/datetime.ts Import UnixTimestamp from enssdk.
packages/ensnode-sdk/src/shared/cache/ttl-cache.ts Import UnixTimestamp from enssdk.
packages/ensnode-sdk/src/shared/cache/swr-cache.ts Import UnixTimestamp from enssdk.
packages/ensnode-sdk/src/registrars/zod-schemas.ts Use normalized-address schema for registrar payloads.
packages/ensnode-sdk/src/registrars/registration-lifecycle.ts Import UnixTimestamp from enssdk.
packages/ensnode-sdk/src/omnigraph-api/example-queries.ts Normalize hardcoded example addresses.
packages/ensnode-sdk/src/indexing-status/realtime-indexing-status-projection.ts Import UnixTimestamp from enssdk.
packages/ensnode-sdk/src/indexing-status/omnichain-indexing-status-snapshot.ts Import UnixTimestamp from enssdk.
packages/ensnode-sdk/src/indexing-status/cross-chain-indexing-status-snapshot.ts Import UnixTimestamp from enssdk.
packages/ensnode-sdk/src/indexing-status/chain-indexing-status-snapshot.ts Import UnixTimestamp from enssdk.
packages/ensnode-sdk/src/ensapi/api/registrar-actions/response.ts Import UnixTimestamp from enssdk.
packages/ensnode-sdk/src/ensapi/api/registrar-actions/request.ts Import UnixTimestamp from enssdk.
packages/ensnode-sdk/src/ensapi/api/registrar-actions/filters.ts Import UnixTimestamp from enssdk.
packages/ensnode-sdk/src/ensapi/api/name-tokens/response.ts Import UnixTimestamp from enssdk.
packages/enskit/src/react/omnigraph/index.ts Re-export omnigraph components.
packages/enskit/src/react/omnigraph/components/index.tsx Barrel export for new component.
packages/enskit/src/react/omnigraph/components/ensure-interpreted-name.tsx Add EnsureInterpretedName helper component.
packages/ens-referrals/src/v1/referrer-metrics.ts Normalize referrers via toNormalizedAddress.
packages/ens-referrals/src/v1/award-models/rev-share-limit/rules.ts Normalize referrer comparisons via toNormalizedAddress.
packages/ens-referrals/src/v1/award-models/rev-share-limit/leaderboard.ts Normalize event referrers via toNormalizedAddress.
packages/ens-referrals/src/v1/award-models/rev-share-limit/api/zod-schemas.ts Switch to normalized-address schema + uniqueness by normalized form.
packages/ens-referrals/src/v1/award-models/pie-split/api/zod-schemas.ts Switch to normalized-address schema.
packages/ens-referrals/src/v1/api/zod-schemas.ts Switch to normalized-address schema for requests.
packages/ens-referrals/src/v1/address.ts Remove local normalizeAddress helper.
packages/ens-referrals/src/referrer-metrics.ts Normalize referrers via toNormalizedAddress.
packages/ens-referrals/src/api/zod-schemas.ts Switch to normalized-address schema.
packages/ens-referrals/src/address.ts Remove local normalizeAddress helper.
packages/datasources/src/invariants.test.ts Adjust address-lowercase invariant comment/check.
examples/enskit-react-example/src/DomainView.tsx Use EnsureInterpretedName + new parent-name helper in example UI.
apps/ensindexer/src/plugins/subgraph/shared-handlers/ThreeDNSToken.ts Treat event args addresses as NormalizedAddress.
apps/ensindexer/src/plugins/subgraph/shared-handlers/Resolver.ts Treat event args addresses as NormalizedAddress.
apps/ensindexer/src/plugins/subgraph/shared-handlers/Registry.ts Treat event args addresses as NormalizedAddress.
apps/ensindexer/src/plugins/subgraph/shared-handlers/Registrar.ts Treat event args addresses as NormalizedAddress.
apps/ensindexer/src/plugins/subgraph/shared-handlers/NameWrapper.ts Treat event args addresses as NormalizedAddress.
apps/ensindexer/src/plugins/subgraph/plugins/subgraph/handlers/Registry.ts Swap ROOT_NODE usage to ENS_ROOT_NODE.
apps/ensindexer/src/plugins/registrars/shared/lib/registrar-events.ts Move UnixTimestamp type import to enssdk.
apps/ensindexer/src/plugins/registrars/shared/lib/registrar-action.ts Add clarifying doc comment re: toLowerCase() keying.
apps/ensindexer/src/plugins/protocol-acceleration/handlers/ThreeDNSToken.ts Treat event args addresses as NormalizedAddress.
apps/ensindexer/src/plugins/protocol-acceleration/handlers/ENSv2Registry.ts Treat event args addresses as NormalizedAddress.
apps/ensindexer/src/plugins/protocol-acceleration/handlers/ENSv1Registry.ts Treat event args addresses as NormalizedAddress.
apps/ensindexer/src/plugins/ensv2/handlers/ensv2/ETHRegistrar.ts Treat event args addresses as NormalizedAddress.
apps/ensindexer/src/plugins/ensv2/handlers/ensv2/ENSv2Registry.ts Treat event args addresses as NormalizedAddress.
apps/ensindexer/src/plugins/ensv2/handlers/ensv2/EnhancedAccessControl.ts Treat event args addresses as NormalizedAddress.
apps/ensindexer/src/plugins/ensv2/handlers/ensv1/NameWrapper.ts Treat event args addresses as NormalizedAddress.
apps/ensindexer/src/plugins/ensv2/handlers/ensv1/ENSv1Registry.ts Swap ROOT_NODE usage to ENS_ROOT_NODE + normalize address types.
apps/ensindexer/src/plugins/ensv2/handlers/ensv1/BaseRegistrar.ts Treat event args addresses as NormalizedAddress.
apps/ensindexer/src/lib/trace-transaction-helpers.ts Normalize extracted trace addresses via toNormalizedAddress.
apps/ensindexer/src/lib/tokenscope/seaport-types.ts Type Seaport event addresses as NormalizedAddress.
apps/ensindexer/src/lib/subgraph/subgraph-helpers.ts Swap ROOT_NODE usage to ENS_ROOT_NODE.
apps/ensindexer/src/lib/heal-addr-reverse-subname-label.ts Treat event owner address as NormalizedAddress.
apps/ensindexer/src/config/validations.ts Use isNormalizedAddress for contract-config validation.
apps/ensapi/src/omnigraph-api/schema/scalars.ts Parse Address scalar via normalized-address schema; update docs.
apps/ensapi/src/omnigraph-api/schema/permissions.integration.test.ts Update tests to expect normalized addresses/topics casing.
apps/ensapi/src/omnigraph-api/schema/domain.integration.test.ts Update tests to expect normalized topics/from casing.
apps/ensapi/src/omnigraph-api/schema/account.integration.test.ts Normalize devnet addresses and update assertions.
apps/ensapi/src/omnigraph-api/lib/get-canonical-path.ts Swap ROOT_NODE usage to ENS_ROOT_NODE.
apps/ensapi/src/omnigraph-api/builder.ts Update Address scalar output typing to NormalizedAddress.
apps/ensapi/src/lib/resolution/resolve-with-universal-resolver.ts Require InterpretedName for resolution call execution.
apps/ensapi/src/lib/resolution/resolve-calls-and-results.ts Tweak error recording logic around reverts vs unexpected errors.
apps/ensapi/src/lib/resolution/packetToBytes.test.ts Add test coverage for encoded-labelhash DNS encoding behavior.
apps/ensapi/src/lib/resolution/forward-resolution.ts Enforce InterpretedName invariant via asInterpretedName.
apps/ensapi/src/lib/protocol-acceleration/find-resolver.ts Use InterpretedName throughout resolver-finding logic.
apps/ensapi/src/lib/name-tokens/find-name-tokens-for-domain.ts Move UnixTimestamp type import to enssdk.
apps/ensapi/src/lib/handlers/params.schema.ts Use normalized-address schema for address param parsing.
apps/ensapi/src/handlers/ensanalytics/ensanalytics-api.routes.ts Use normalized-address schema for referrer params.
apps/ensapi/src/handlers/ensanalytics/ensanalytics-api-v1.routes.ts Use normalized-address schema for referrer params.
apps/ensapi/src/handlers/api/meta/realtime-api.test.ts Move UnixTimestamp type import to enssdk.
apps/ensapi/src/handlers/api/explore/registrar-actions-api.routes.ts Use normalized-address schema for decodedReferrer filter.
apps/ensapi/src/handlers/api/explore/name-tokens-api.ts Swap root constants + parent-name helper usage.
apps/ensadmin/src/components/indexing-status/backfill-status.tsx Move UnixTimestamp type import to enssdk.
apps/ensadmin/src/app/mock/display-identity/page.tsx Normalize selected addresses via toNormalizedAddress.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps bot commented Apr 9, 2026

Greptile Summary

This PR continues the enssdk refactor: NormalizedName is removed in favour of InterpretedName project-wide, NormalizedAddress (unbranded alias for Address) replaces ad-hoc lowercase-address handling, and the new enskit/react submodule is introduced with EnsureInterpretedName relocated there.

Mechanically the changes are clean and well-tested. A few improvements are worth noting:

  • The EnsureInterpretedName component no longer has the fast-path isInterpretedName short-circuit that previously bypassed the allowENSRootName: false guard for empty strings.
  • The omnigraph cache exchange gains localBigIntResolvers (string → native bigint at read time), enabled by switching the urql introspection from the @urql/introspection minified format (which encoded all scalars as "Any") to the gql.tada-generated format that preserves actual scalar names.
  • The AccountId key function now guards against missing address/chainId, and the account resolver's throw new Error("never") is replaced with a safe cache passthrough.

Confidence Score: 5/5

  • Safe to merge — all changes are intentional, well-tested, and the prior P1 concerns from the previous review round have been addressed.
  • No P0 or P1 issues found. The EnsureInterpretedName root-name bypass is fixed, decodeEncodedReferrer correctly returns a NormalizedAddress, the BigInt deserialization depends on the correct introspection format (now present), and the NormalizedAddress unbranded trade-off is acknowledged and accepted by the author. All remaining findings are P2 or lower.
  • No files require special attention.

Important Files Changed

Filename Overview
packages/enssdk/src/lib/interpreted-names-and-labels.ts Expanded literalNameToInterpretedName with full option set; new helpers (isInterpretedName, constructSubInterpretedName, parsePartialInterpretedName) look correct. No issues found.
packages/enskit/src/react/omnigraph/_lib/local-bigint-resolvers.ts New resolver that deserializes cached BigInt strings to native bigints at read time. Correctly handles null/undefined, list-wrapped types, and doubly-nested non-null wrappers. Relies on the regenerated gql.tada introspection (which uses actual scalar names instead of "Any") to discover BigInt fields.
packages/enskit/src/react/omnigraph/_lib/cache-exchange.ts Refactored from the monolithic lib/cache-exchange.ts into composable pieces. Key improvements: AccountId key guard added (null checks for address/chainId), byIdLookupResolvers extracted, BigInt local resolvers wired in, and the account resolver's throw new Error("never") replaced with a safe passthrough.
packages/enskit/src/react/components/ensure-interpreted-name.tsx Moved from its original location and simplified: the fast-path isInterpretedName short-circuit (which previously bypassed the allowENSRootName option for empty strings) is removed. Now always routes through literalNameToInterpretedName, which correctly enforces all options including the ENS root name check.
packages/ensnode-sdk/src/registrars/encoded-referrer.ts decodeEncodedReferrer now returns a lowercase NormalizedAddress (via toNormalizedAddress) instead of a checksummed Address. buildEncodedReferrer now validates the address is already normalized before building. zeroAddress is lowercase so it satisfies NormalizedAddress. No issues.
packages/enssdk/src/lib/types/evm.ts Introduces NormalizedAddress = Address (intentionally unbranded), UnixTimestampBigInt, DurationBigInt, and Wei semantic type aliases. The AccountId.address field is tightened to NormalizedAddress. Trade-offs of the unbranded alias design are acknowledged in the PR.
packages/enssdk/src/omnigraph/generated/introspection.ts Regenerated from the gql.tada toolchain, replacing the minified @urql/introspection format. Critical difference: scalar field types are now named (e.g., "BigInt") instead of "Any", which is what enables localBigIntResolvers to discover BigInt fields at runtime.
packages/enskit/tsup.config.ts Adds react/index entry point for the new enskit/react submodule. Matches the package.json export map additions. No issues.
packages/enssdk/src/lib/names.ts getNameHierarchy updated to return [] for ENS root (was [""]). getParentNameFQDN renamed to getParentInterpretedName and now returns null (was throwing) for the root. Both changes are tested and appear intentional.
packages/enskit/src/react/omnigraph/_lib/by-id-lookup-resolvers.ts Extracted from the old monolithic cache-exchange. The account resolver now uses passthrough instead of throw new Error("never") when neither by.id nor by.address is present — more resilient behavior. All other resolvers unchanged.

Sequence Diagram

sequenceDiagram
    participant Consumer as React Component
    participant urql as urql Client
    participant Cache as graphcache (omnigraphCacheExchange)
    participant BigIntResolver as localBigIntResolvers
    participant Network as Omnigraph API

    Consumer->>urql: "useOmnigraphQuery({ query, variables })"
    urql->>Cache: Check normalized cache
    alt Cache miss
        Cache->>Network: HTTP request
        Network-->>Cache: JSON response (BigInt fields as strings e.g. "1234567890")
        Cache->>Cache: "Normalize & store raw string values"
    end
    Cache->>BigIntResolver: resolve field (e.g. registration.start)
    Note over BigIntResolver: parent["start"] = "1234567890" (string)<br/>BigInt("1234567890") → 1234567890n
    BigIntResolver-->>Cache: 1234567890n (native bigint)
    Cache-->>urql: Typed result (BigInt fields as bigint)
    urql-->>Consumer: data.domain.registration.start: bigint
Loading

Reviews (4): Last reviewed commit: "fix: name test again" | Re-trigger Greptile

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 11

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
packages/ens-referrals/src/referrer-metrics.ts (1)

67-79: ⚠️ Potential issue | 🔴 Critical

Replace lowercase validation with normalized-address validation.

buildReferrerMetrics (Line 67) normalizes with toNormalizedAddress, which returns EIP-55 checksummed addresses (mixed-case per viem/enssdk documentation). However, validateReferrerMetrics (Line 78) enforces lowercase via validateLowercaseAddress, which will reject all checksummed addresses. This causes every call to throw—a blocking bug.

Suggested fix
-import { validateLowercaseAddress } from "./address";
@@
 export const validateReferrerMetrics = (metrics: ReferrerMetrics): void => {
-  validateLowercaseAddress(metrics.referrer);
+  if (toNormalizedAddress(metrics.referrer) !== metrics.referrer) {
+    throw new Error(
+      `ReferrerMetrics.referrer must be normalized. Got: ${metrics.referrer}.`,
+    );
+  }
   validateNonNegativeInteger(metrics.totalReferrals);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/ens-referrals/src/referrer-metrics.ts` around lines 67 - 79,
buildReferrerMetrics normalizes referrer with toNormalizedAddress (EIP-55
checksummed), but validateReferrerMetrics still calls validateLowercaseAddress
causing valid checksummed addresses to be rejected; replace the lowercase check
with the matching normalized/checksummed validator — e.g., in
validateReferrerMetrics remove validateLowercaseAddress(metrics.referrer) and
call validateNormalizedAddress(metrics.referrer) (or the project's
EIP-55/normalized address validator) so the validation matches
toNormalizedAddress, keeping the existing
validateNonNegativeInteger(metrics.totalReferrals) check.
apps/ensindexer/src/plugins/subgraph/shared-handlers/NameWrapper.ts (1)

119-126: 🧹 Nitpick | 🔵 Trivial

Internal handleTransfer function still uses Address type.

The internal helper handleTransfer uses to: Address (line 125), but it receives NormalizedAddress values from handleTransferSingle and handleTransferBatch. Consider updating this to NormalizedAddress for consistency.

♻️ Proposed fix for type consistency
   async function handleTransfer(
     context: IndexingEngineContext,
     event: EventWithArgs,
     eventId: string,
     tokenId: bigint,
-    to: Address,
+    to: NormalizedAddress,
   ) {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/ensindexer/src/plugins/subgraph/shared-handlers/NameWrapper.ts` around
lines 119 - 126, The internal handler handleTransfer currently declares the
recipient parameter as to: Address but callers (handleTransferSingle and
handleTransferBatch) pass NormalizedAddress; update handleTransfer's signature
to use to: NormalizedAddress for type consistency, adjust any imports to include
NormalizedAddress instead of Address, and remove or update any inline
casts/usages inside handleTransfer that assume Address so they work with
NormalizedAddress.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@apps/ensapi/src/lib/resolution/resolve-calls-and-results.ts`:
- Around line 200-204: The catch block that currently only calls
span.recordException(error) when error instanceof Error should be changed to
record all throwables: always call span.recordException with an Error instance
by using the original Error if error instanceof Error, otherwise create a new
Error(String(error ?? 'non-error thrown')) before recording; keep the subsequent
throw error to rethrow the original value. Update the code around the catch in
resolve-calls-and-results (where span.recordException is invoked) to handle
null/undefined and non-Error objects as described.

In `@apps/ensapi/src/omnigraph-api/schema/scalars.ts`:
- Around line 39-43: The scalar type declaration for Address is misleading:
builder.scalarType("Address", ...) still describes addresses as "in all
lowercase" but the parse logic uses makeNormalizedAddressSchema which returns
EIP-55 checksummed (mixed-case) addresses; update the description to reflect
checksummed addresses or normalized EIP-55 format and ensure serialize/parse
semantics match that description (reference builder.scalarType("Address"), the
Address type, and makeNormalizedAddressSchema).

In `@apps/ensindexer/src/config/validations.ts`:
- Around line 130-133: The validation currently sets isValidAddress using both
isAddress(...) and isNormalizedAddress(...); remove the redundant isAddress call
and set isValidAddress by only calling
isNormalizedAddress(contractConfig.address as Address) (keep the variable name
isValidAddress and the contractConfig.address reference) so the check still
ensures lowercase normalized address without duplicating validation work.

In `@examples/enskit-react-example/src/DomainView.tsx`:
- Around line 85-108: Fix the typo in the inline comment inside the DomainView
component: change "redirec to /domain/etc" to "redirect to /domain/etc" (the
comment immediately above the Navigate fallback that checks params.name in the
DomainView function using useParams and Navigate).

In `@packages/datasources/src/invariants.test.ts`:
- Line 26: The assertion message in invariants.test.ts contains a grammar
mistake in the template literal for the contract address error; update the
string `The ContractConfig '${namespace}' > '${datasourceName}' >
'${contractName}' > '${contractConfig.address}' is not is lowercase format.` to
read `The ContractConfig '${namespace}' > '${datasourceName}' >
'${contractName}' > '${contractConfig.address}' is not in lowercase format.` so
the phrase uses "in lowercase format" (locate the template literal in the test
that references namespace, datasourceName, contractName, and
contractConfig.address).

In
`@packages/ens-referrals/src/v1/award-models/rev-share-limit/api/zod-schemas.ts`:
- Around line 58-60: The duplicate-check refinement currently re-normalizes
addresses by calling toNormalizedAddress(item.referrer) even though
item.referrer is already normalized by the schema; in the refinement callback
replace the toNormalizedAddress call and map directly using item.referrer (i.e.,
const addresses = items.map(item => item.referrer)) so the new Set size
comparison stays the same, and remove the unnecessary toNormalizedAddress
invocation to avoid redundant work in the refinement.

In `@packages/ens-referrals/src/v1/award-models/rev-share-limit/rules.ts`:
- Around line 166-169: Change the model so disqualifications[].referrer is typed
as NormalizedAddress and ensure referrer values are normalized at the model
boundary (where disqualifications are created/loaded) rather than at every
consumer; update the disqualifications type alias and any factories/parsers to
call toNormalizedAddress once when constructing a disqualification, then in
rules.ts remove the runtime toNormalizedAddress(referrer) and the
normalizedReferrer local and compare rules.disqualifications[*].referrer
directly to referrer (now already a NormalizedAddress) so normalization is
enforced at the type level.

In `@packages/ensnode-sdk/src/registrars/zod-schemas.ts`:
- Around line 130-133: The invariant
invariant_registrarActionDecodedReferrerBasedOnRawReferrer currently compares
decodedReferrer against rawReferrer using .toLowerCase(); update it to use the
same normalization as decodedReferrer by importing toNormalizedAddress from
"enssdk" and replacing the .toLowerCase() usage with
toNormalizedAddress(rawReferrer) (so both sides use
makeNormalizedAddressSchema/toNormalizedAddress), and add the import for
toNormalizedAddress at the top of the file.

In `@packages/enssdk/src/lib/constants.ts`:
- Around line 8-13: ENS_ROOT_NODE currently recreates the empty interpreted name
inline; change ENS_ROOT_NODE to use the existing ENS_ROOT_NAME constant as its
single source of truth by passing ENS_ROOT_NAME into namehashInterpretedName
(keep the Node type), i.e., replace the asInterpretedName("") usage in the
ENS_ROOT_NODE initializer with ENS_ROOT_NAME so the empty name is defined only
once and cannot drift.

In `@packages/enssdk/src/lib/interpreted-names-and-labels.ts`:
- Around line 218-224: The JSDoc for asLiteralLabel incorrectly claims it
"Validates and casts" while the implementation only performs a type cast; update
the documentation or implementation: either reintroduce runtime validation
inside the asLiteralLabel(label: Label): LiteralLabel function (perform checks
on format/characters and throw a clear error on invalid input) or change the
JSDoc to say it "Casts" (e.g., "Casts a string to a LiteralLabel without runtime
validation") so the comment accurately reflects the behavior; reference the
asLiteralLabel function to locate the change.
- Around line 29-40: nameToInterpretedName incorrectly transforms the ENS root
("") because "".split(".") yields [""] which gets encoded as a non-root label;
fix by handling the root early: in nameToInterpretedName, if name === "" return
interpretedLabelsToInterpretedName([]) (i.e., an empty labels array) before
calling .split and the label mapping logic so you don't encode a root label;
keep the rest of the mapping using asInterpretedLabel, isEncodedLabelHash,
isNormalizedLabel, encodeLabelHash, and labelhashLiteralLabel as-is for non-root
names.

---

Outside diff comments:
In `@apps/ensindexer/src/plugins/subgraph/shared-handlers/NameWrapper.ts`:
- Around line 119-126: The internal handler handleTransfer currently declares
the recipient parameter as to: Address but callers (handleTransferSingle and
handleTransferBatch) pass NormalizedAddress; update handleTransfer's signature
to use to: NormalizedAddress for type consistency, adjust any imports to include
NormalizedAddress instead of Address, and remove or update any inline
casts/usages inside handleTransfer that assume Address so they work with
NormalizedAddress.

In `@packages/ens-referrals/src/referrer-metrics.ts`:
- Around line 67-79: buildReferrerMetrics normalizes referrer with
toNormalizedAddress (EIP-55 checksummed), but validateReferrerMetrics still
calls validateLowercaseAddress causing valid checksummed addresses to be
rejected; replace the lowercase check with the matching normalized/checksummed
validator — e.g., in validateReferrerMetrics remove
validateLowercaseAddress(metrics.referrer) and call
validateNormalizedAddress(metrics.referrer) (or the project's EIP-55/normalized
address validator) so the validation matches toNormalizedAddress, keeping the
existing validateNonNegativeInteger(metrics.totalReferrals) check.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 08e38f45-8726-4f05-bc61-391d4ba45bf1

📥 Commits

Reviewing files that changed from the base of the PR and between b781245 and 4b5fa3d.

⛔ Files ignored due to path filters (1)
  • packages/enssdk/src/omnigraph/generated/schema.graphql is excluded by !**/generated/**
📒 Files selected for processing (87)
  • apps/ensadmin/src/app/mock/display-identity/page.tsx
  • apps/ensadmin/src/components/indexing-status/backfill-status.tsx
  • apps/ensapi/src/handlers/api/explore/name-tokens-api.ts
  • apps/ensapi/src/handlers/api/explore/registrar-actions-api.routes.ts
  • apps/ensapi/src/handlers/api/meta/realtime-api.test.ts
  • apps/ensapi/src/handlers/ensanalytics/ensanalytics-api-v1.routes.ts
  • apps/ensapi/src/handlers/ensanalytics/ensanalytics-api.routes.ts
  • apps/ensapi/src/lib/handlers/params.schema.ts
  • apps/ensapi/src/lib/name-tokens/find-name-tokens-for-domain.ts
  • apps/ensapi/src/lib/protocol-acceleration/find-resolver.ts
  • apps/ensapi/src/lib/resolution/forward-resolution.ts
  • apps/ensapi/src/lib/resolution/packetToBytes.test.ts
  • apps/ensapi/src/lib/resolution/resolve-calls-and-results.ts
  • apps/ensapi/src/lib/resolution/resolve-with-universal-resolver.ts
  • apps/ensapi/src/omnigraph-api/builder.ts
  • apps/ensapi/src/omnigraph-api/lib/get-canonical-path.ts
  • apps/ensapi/src/omnigraph-api/schema/account.integration.test.ts
  • apps/ensapi/src/omnigraph-api/schema/domain.integration.test.ts
  • apps/ensapi/src/omnigraph-api/schema/permissions.integration.test.ts
  • apps/ensapi/src/omnigraph-api/schema/scalars.ts
  • apps/ensindexer/src/config/validations.ts
  • apps/ensindexer/src/lib/heal-addr-reverse-subname-label.ts
  • apps/ensindexer/src/lib/subgraph/subgraph-helpers.ts
  • apps/ensindexer/src/lib/tokenscope/seaport-types.ts
  • apps/ensindexer/src/lib/trace-transaction-helpers.ts
  • apps/ensindexer/src/plugins/ensv2/handlers/ensv1/BaseRegistrar.ts
  • apps/ensindexer/src/plugins/ensv2/handlers/ensv1/ENSv1Registry.ts
  • apps/ensindexer/src/plugins/ensv2/handlers/ensv1/NameWrapper.ts
  • apps/ensindexer/src/plugins/ensv2/handlers/ensv2/ENSv2Registry.ts
  • apps/ensindexer/src/plugins/ensv2/handlers/ensv2/ETHRegistrar.ts
  • apps/ensindexer/src/plugins/ensv2/handlers/ensv2/EnhancedAccessControl.ts
  • apps/ensindexer/src/plugins/protocol-acceleration/handlers/ENSv1Registry.ts
  • apps/ensindexer/src/plugins/protocol-acceleration/handlers/ENSv2Registry.ts
  • apps/ensindexer/src/plugins/protocol-acceleration/handlers/ThreeDNSToken.ts
  • apps/ensindexer/src/plugins/registrars/shared/lib/registrar-action.ts
  • apps/ensindexer/src/plugins/registrars/shared/lib/registrar-events.ts
  • apps/ensindexer/src/plugins/subgraph/plugins/subgraph/handlers/Registry.ts
  • apps/ensindexer/src/plugins/subgraph/shared-handlers/NameWrapper.ts
  • apps/ensindexer/src/plugins/subgraph/shared-handlers/Registrar.ts
  • apps/ensindexer/src/plugins/subgraph/shared-handlers/Registry.ts
  • apps/ensindexer/src/plugins/subgraph/shared-handlers/Resolver.ts
  • apps/ensindexer/src/plugins/subgraph/shared-handlers/ThreeDNSToken.ts
  • examples/enskit-react-example/src/DomainView.tsx
  • packages/datasources/src/invariants.test.ts
  • packages/ens-referrals/src/address.ts
  • packages/ens-referrals/src/api/zod-schemas.ts
  • packages/ens-referrals/src/referrer-metrics.ts
  • packages/ens-referrals/src/v1/address.ts
  • packages/ens-referrals/src/v1/api/zod-schemas.ts
  • packages/ens-referrals/src/v1/award-models/pie-split/api/zod-schemas.ts
  • packages/ens-referrals/src/v1/award-models/rev-share-limit/api/zod-schemas.ts
  • packages/ens-referrals/src/v1/award-models/rev-share-limit/leaderboard.ts
  • packages/ens-referrals/src/v1/award-models/rev-share-limit/rules.ts
  • packages/ens-referrals/src/v1/referrer-metrics.ts
  • packages/enskit/src/react/omnigraph/components/ensure-interpreted-name.tsx
  • packages/enskit/src/react/omnigraph/components/index.tsx
  • packages/enskit/src/react/omnigraph/index.ts
  • packages/ensnode-sdk/src/ensapi/api/name-tokens/response.ts
  • packages/ensnode-sdk/src/ensapi/api/registrar-actions/filters.ts
  • packages/ensnode-sdk/src/ensapi/api/registrar-actions/request.ts
  • packages/ensnode-sdk/src/ensapi/api/registrar-actions/response.ts
  • packages/ensnode-sdk/src/indexing-status/chain-indexing-status-snapshot.ts
  • packages/ensnode-sdk/src/indexing-status/cross-chain-indexing-status-snapshot.ts
  • packages/ensnode-sdk/src/indexing-status/omnichain-indexing-status-snapshot.ts
  • packages/ensnode-sdk/src/indexing-status/realtime-indexing-status-projection.ts
  • packages/ensnode-sdk/src/omnigraph-api/example-queries.ts
  • packages/ensnode-sdk/src/registrars/registration-lifecycle.ts
  • packages/ensnode-sdk/src/registrars/zod-schemas.ts
  • packages/ensnode-sdk/src/shared/cache/swr-cache.ts
  • packages/ensnode-sdk/src/shared/cache/ttl-cache.ts
  • packages/ensnode-sdk/src/shared/datetime.ts
  • packages/ensnode-sdk/src/shared/interpretation/interpret-record-values.ts
  • packages/ensnode-sdk/src/shared/types.ts
  • packages/ensnode-sdk/src/shared/zod-schemas.ts
  • packages/ensnode-sdk/src/tokenscope/name-token.ts
  • packages/enssdk/src/lib/address.test.ts
  • packages/enssdk/src/lib/address.ts
  • packages/enssdk/src/lib/constants.ts
  • packages/enssdk/src/lib/interpreted-names-and-labels.ts
  • packages/enssdk/src/lib/names.test.ts
  • packages/enssdk/src/lib/names.ts
  • packages/enssdk/src/lib/normalization.ts
  • packages/enssdk/src/lib/parse-reverse-name.ts
  • packages/enssdk/src/lib/types/ens.ts
  • packages/enssdk/src/lib/types/evm.ts
  • packages/enssdk/src/omnigraph/graphql.ts
  • packages/namehash-ui/src/components/registrar-actions/RegistrarActionCard.tsx
💤 Files with no reviewable changes (3)
  • packages/ens-referrals/src/address.ts
  • packages/ens-referrals/src/v1/address.ts
  • packages/enssdk/src/lib/types/ens.ts

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

♻️ Duplicate comments (2)
packages/enssdk/src/lib/interpreted-names-and-labels.ts (2)

219-224: ⚠️ Potential issue | 🟡 Minor

Make the asLiteralLabel docs match the implementation.

Line 220 still says this helper “validates and casts,” but Lines 223-224 now do a plain cast only. Either restore validation or update the JSDoc to avoid implying runtime checks.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/enssdk/src/lib/interpreted-names-and-labels.ts` around lines 219 -
224, The JSDoc for asLiteralLabel incorrectly claims it "validates and casts"
while the implementation only does a TypeScript cast; either implement runtime
validation inside asLiteralLabel (e.g., check Label shape and throw or return a
safe result) or update the JSDoc to remove "validates" and state it simply
performs a TypeScript cast/typing assertion. Refer to the function name
asLiteralLabel and ensure the chosen change is consistent across the file
(update tests/docs if needed).

30-40: ⚠️ Potential issue | 🟠 Major

Handle the ENS root before splitting labels.

Line 33 still turns "" into [""], so nameToInterpretedName("") encodes an empty label instead of preserving the root name.

💡 Suggested fix
 export function nameToInterpretedName(name: Name): InterpretedName {
+  if (name === "") return interpretedLabelsToInterpretedName([]);
+
   return interpretedLabelsToInterpretedName(
     name
       .split(".")
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/enssdk/src/lib/interpreted-names-and-labels.ts` around lines 30 -
40, The function nameToInterpretedName currently splits the ENS root ("") into
[""] and then encodes that empty label; instead, detect the root case up-front
and return the interpreted-root representation (i.e., call
interpretedLabelsToInterpretedName with an empty array) when name === "" (or
canonical root form), otherwise proceed with the existing split-and-map logic;
update nameToInterpretedName to short-circuit on the empty root before
performing split and referencing helpers like isEncodedLabelHash,
isNormalizedLabel, encodeLabelHash, labelhashLiteralLabel, asLiteralLabel, and
asInterpretedLabel.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@apps/ensindexer/src/config/validations.ts`:
- Line 130: Fix the grammar in the error message string in validations.ts:
change "not a enssdk#NormalizedAddress" to "not an enssdk#NormalizedAddress"
where the message is composed using config.namespace, datasourceName,
contractName and contractConfig.address so the corrected article applies to the
identifier enssdk#NormalizedAddress in that error text.

In `@examples/enskit-react-example/src/DomainView.tsx`:
- Line 58: The UI currently returns a message exposing internal type name
"InterpretedName" (in the conditional that checks data?.domain), so update the
user-facing text in DomainView (the early return that uses data?.domain and
name) to a friendly phrase like "A domain named '{name}' was not found." or "No
domain found with the name '{name}'.", replacing "InterpretedName" with plain
language.

In `@packages/ens-referrals/src/address.ts`:
- Line 6: Update the thrown error message in
packages/ens-referrals/src/address.ts to use the new NormalizedAddress
terminology: replace the existing message "Invalid address: '${address}'.
Address must be a lowercase EVM Address." with a message that references
"NormalizedAddress" (e.g., "Invalid address: '${address}'. Address must be a
NormalizedAddress.") so diagnostics match the refactor; locate the throw new
Error(...) in the address validation logic where the variable address is used
and change only the message text.

In `@packages/ensdb-sdk/src/ensindexer-abstract/protocol-acceleration.schema.ts`:
- Around line 39-41: Create a shared alias (e.g., NonEmptyInterpretedName) that
documents the “non-empty InterpretedName” invariant and replace the inline
typing on both columns with that alias; specifically add a type alias named
NonEmptyInterpretedName documenting the non-empty contract and then change
occurrences like value: t.text().notNull().$type<InterpretedName>() (and the
other occurrence around lines 131-133) to use $type<NonEmptyInterpretedName>()
so the invariant is declared once and reused.

In `@packages/enssdk/src/lib/address.test.ts`:
- Around line 47-53: Tests currently assert a broad /does not/ message which may
match unrelated errors; update the two specs ("should throw for a partial
address" and "should throw for a non-hex string") to assert the actual error
shape/message thrown by toNormalizedAddress instead of the vague regex — either
use toThrowError(/exact expected message/) with the precise message the function
produces (e.g., /invalid address/i) or assert the concrete error type with
toThrow(TypeError) if it throws a TypeError; change the expectations around
calls to toNormalizedAddress(...) accordingly.

---

Duplicate comments:
In `@packages/enssdk/src/lib/interpreted-names-and-labels.ts`:
- Around line 219-224: The JSDoc for asLiteralLabel incorrectly claims it
"validates and casts" while the implementation only does a TypeScript cast;
either implement runtime validation inside asLiteralLabel (e.g., check Label
shape and throw or return a safe result) or update the JSDoc to remove
"validates" and state it simply performs a TypeScript cast/typing assertion.
Refer to the function name asLiteralLabel and ensure the chosen change is
consistent across the file (update tests/docs if needed).
- Around line 30-40: The function nameToInterpretedName currently splits the ENS
root ("") into [""] and then encodes that empty label; instead, detect the root
case up-front and return the interpreted-root representation (i.e., call
interpretedLabelsToInterpretedName with an empty array) when name === "" (or
canonical root form), otherwise proceed with the existing split-and-map logic;
update nameToInterpretedName to short-circuit on the empty root before
performing split and referencing helpers like isEncodedLabelHash,
isNormalizedLabel, encodeLabelHash, labelhashLiteralLabel, asLiteralLabel, and
asInterpretedLabel.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 9f31fc64-0b5d-4403-bdb0-b4d60d9244eb

📥 Commits

Reviewing files that changed from the base of the PR and between 4b5fa3d and 5d4e6c9.

📒 Files selected for processing (11)
  • apps/ensapi/src/lib/resolution/forward-resolution.ts
  • apps/ensindexer/src/config/validations.ts
  • examples/enskit-react-example/src/DomainView.tsx
  • packages/ens-referrals/src/address.ts
  • packages/ens-referrals/src/referrer-metrics.ts
  • packages/ens-referrals/src/v1/address.ts
  • packages/ens-referrals/src/v1/award-models/rev-share-limit/rules.ts
  • packages/ens-referrals/src/v1/referrer-metrics.ts
  • packages/ensdb-sdk/src/ensindexer-abstract/protocol-acceleration.schema.ts
  • packages/enssdk/src/lib/address.test.ts
  • packages/enssdk/src/lib/interpreted-names-and-labels.ts

Copy link
Copy Markdown
Member

@lightwalker-eth lightwalker-eth left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@shrugs Awesome updates here 😄 Reviewed and shared some suggestions 👍 Appreciate your advice!

options: Omit<Parameters<typeof _resolveForward>[2], "registry">,
): Promise<ForwardResolutionResult<SELECTION>> {
// Invariant: Name must be an InterpretedName
const interpretedName = asInterpretedName(name);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have a related issue open: #1032

What do you suggest we do in relation to issue 1032 within the scope of this PR (PR 1908)? Should we work to confirm that issue 1032 can be successfully closed, or maybe keep issue 1032 open and make any new relevant comments on it that might help us with working on it later?

* Validates and casts a string to a {@link LiteralLabel}.
* A LiteralLabel is a label as it literally appears onchain.
*/
export function asLiteralLabel(label: Label): LiteralLabel {
Copy link
Copy Markdown
Member

@lightwalker-eth lightwalker-eth Apr 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we completely remove the Label and Name type aliases? I worry they will be a source of problems and that only our more precise type names should be used.

The only case I can think of right now that's not covered by our more formal type names would be what happens when we beautify an InterpretedName. This doesn't return an InterpretedName. Instead it returns what we might give a new type alias for: a BeautifiedName, which is the same as an InterpretedName except it loosens the constraints such that a label might be normalizable but not necessarily normalized.

In other words:

  • An InterpretedName is all normalized labels or encoded labelhashes.
  • A BeautifiedName is all normalizable labels or encoded labelhashes.

When we display names in a UI we should render them as BeautifiedName values.

Please also note that I believe raffy's beautify name function won't properly handle labels that are encoded labelhashes and would throw on those. So we would need to implement our own wrapper around raffy's beautify name function to correctly convert any InterpretedName into a BeautifiedName.

Appreciate your advice 👍

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@shrugs I continue to think it would be nice if we completely removed all use of the generic Name or Label types across our whole monorepo.

Please see my other comments suggesting the introduce new types for UserInputName and UserInputLabel.

We can then also add types for BeautifiedName and BeautifiedLabel based on the definition I shared in the parent comment I'm now replying to.

For our utility functions that work on unknown name / label values, those could operate on raw string values as we haven't validated yet if they are an InterpretedName (etc..) or not.

*/
export function asLiteralLabel(label: string): LiteralLabel {
if (label === "") throw new Error("LiteralLabel must not be empty");
export function asInterpretedName(name: Name): InterpretedName {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This feedback is in relation to your work on nameToInterpretedName which is really awesome.

A worry I have is that devs using this package will be lazy with how they use asInterpretedName. Specifically worried that they will use it when parsing names from user input instead of using nameToInterpretedName.

Perhaps we should rename asInterpretedName to something that makes it more explicit it is just for "system inputs" and not user inputs? Appreciate your advice.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmm, i see the concern, but i'm loath to change the existing as* and to* pattern for these branded types. hopefully with enough example cases and public-facing usage of the literalNameToInterpretedName function this won't be an issue?

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 169 out of 174 changed files in this pull request and generated 3 comments.

Files not reviewed (1)
  • pnpm-lock.yaml: Language not supported

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 169 out of 174 changed files in this pull request and generated 3 comments.

Files not reviewed (1)
  • pnpm-lock.yaml: Language not supported

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copy link
Copy Markdown
Member

@lightwalker-eth lightwalker-eth left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@shrugs Looks good nice work! Happy to merge when you're ready ✅

Copilot AI review requested due to automatic review settings April 14, 2026 19:36
@shrugs shrugs merged commit 12439ac into main Apr 14, 2026
12 of 17 checks passed
@shrugs shrugs deleted the refactor/enssdk-refactor-continued branch April 14, 2026 19:37
@github-actions github-actions bot mentioned this pull request Apr 14, 2026
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 169 out of 174 changed files in this pull request and generated 2 comments.

Files not reviewed (1)
  • pnpm-lock.yaml: Language not supported

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +19 to +24
export const getNameHierarchy = (name: InterpretedName): InterpretedName[] => {
if (name === ENS_ROOT_NAME) return [];

return interpretedNameToInterpretedLabels(name).map((_, i, labels) =>
interpretedLabelsToInterpretedName(labels.slice(i)),
);
Copy link

Copilot AI Apr 14, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

getNameHierarchy(ENS_ROOT_NAME) now returns []. At least one consumer (apps/ensapi/src/lib/protocol-acceleration/find-resolver.tsfindResolverWithIndex) treats an empty hierarchy as an invariant violation and throws, which means protocol-accelerated resolution can crash for the root name ("").

Either include ENS_ROOT_NAME in the returned hierarchy (e.g. [ENS_ROOT_NAME]) or ensure downstream resolver-lookup code treats the root name as a valid special-case and returns a null/empty result instead of throwing.

Copilot uses AI. Check for mistakes.
Comment on lines +59 to +66
export type BuilderScalars = {
ID: { Input: string; Output: string };
BigInt: { Input: bigint; Output: bigint };
Address: { Input: Address; Output: NormalizedAddress };
Hex: { Input: Hex; Output: Hex };
ChainId: { Input: ChainId; Output: ChainId };
CoinType: { Input: CoinType; Output: CoinType };
Node: { Input: Node; Output: Node };
Copy link

Copilot AI Apr 14, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BuilderScalars declares the GraphQL Address scalar input type as Address, but apps/ensapi/src/omnigraph-api/schema/scalars.ts now parses and normalizes all Address inputs via makeNormalizedAddressSchema, so resolver args will always receive a NormalizedAddress.

To keep the schema builder types accurate (and avoid accidentally treating non-normalized inputs as possible in resolver code), consider changing BuilderScalars["Address"].Input to NormalizedAddress (or to a union/type that reflects the actual post-parse shape).

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

enssdk: Further migrate types and libs to enssdk

3 participants